一、从一个简单的案例开始
fs.readdir(path.join(__dirname, './index.js'), (err, files) => {
files.foreach((filename, index) => {
fs.readFile((filename, 'utf-8', (err, file) => {
...
}))
})
})
nodejs 特点是单线程、异步、非阻塞,如果代码逻辑涉及到多个回调,就会出现非常可怕的代码,不利于后期的维护。
二、 nodejs为什么会设计成异步编程?
异步编程是随着ajax才火的,所以最熟悉异步编程的就是前端工程师。但在其他编程语言中,异步并不多见,PHP从头到尾就是同步阻塞来执行的,这导致它在复杂的网络应用中无法更好的并发。当然我们并不是在批判PHP,毕竟PHP是世界上最好的语言。PHP代码设计成同步有利于程序员顺序编写业务逻辑,这个有点是不能忽视的。
js就是异步的,浏览器在执行js与UI渲染共用一个进程,如果js采用同步编程,会十分影响用户体验。为什么js不是多线程呢?首先创建线程和执行线程上下文切换的开销较大,其次多线程编程经常面临锁、状态同步等问题。js单线程的编写方式比较符合人按顺序思考的方式,是主流的编程方式。但是单线程无法对硬件资源充分的利用,node利用单线程,远离多线程、状态同步等问题,利用异步I/O,让单线程远离阻塞,以更好的利用CPU。node提供来类似于前端的Web Workers子进程来高效利用CPU。node基于事件循环的执行模式,使得回调函数十分普遍,对于一般的非异步的回调函数,函数由我们自行调用。
三、异步编程的难点
1.异常的处理
node通常会将异常作为回调函数的第一个实参传回,如果第一个参数为null,那么就说明异步调用没有异常抛出。
2.回调函数嵌套过深
开头的案例展示来多层回调的嵌套,导致代码非常难理解,但是现在可以通过 Promise、Generators、async函数解决。
其他还有多线程编程、异步转同步等。
四、异步编程解决方案
1.Promise/Deferred模式
Promise/Deferred模式一定程度上缓解了嵌套回调的问题,Promise只会处在未完成、完成态、失败态中的一种,只会从未完成转化为完成态或者失败态,不能逆转。且完成态和失败态不能相互转化。
Promise对象具备then方法,接受完成态、失败态的调用,只接受function对象,其余对象将被忽略。then方法继续返回Promise对象,以实现链式调用。
function asyncFunction() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Async Hello world');
}, 16);
});
}
asyncFunction().then(function (value) {
console.log(value); // => 'Async Hello world'
}).catch(function (error) {
console.log(error);
});//基本的使用
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。